﻿#include "OiPCH.hpp"

namespace Oi
{
    namespace PLScannerCore
    {
        inline double pointToLineDistance(cv::Point2f* point, cv::Point2f* point1, cv::Point2f* point2)
        {
            return std::fabs((point2->y - point1->y) * point->x - (point2->x - point1->x) * point->y + point2->x * point1->y - point2->y * point1->x) / std::sqrt((point2->y - point1->y) * (point2->y - point1->y) + (point2->x - point1->x) * (point2->x - point1->x));
        }

        class LTPreviewerImpl : public Impl<LTPreviewer>
        {
        public:
            void init();
            void exit();

        public:
            static void refresh(const QMap<QString, Core::RangeMapPtr>& frame, const QDateTime& timestamp, void* data);

        public:
            CLTProfileView* _viewer;
            Appl::Chart* _chart;
            QMap<QString, Core::RangeMapPtr> _currentFrame;
            QTimer* _updateTimer;
            bool _autorange = true;
            QDoubleSpinBox* _exposure;
            QDoubleSpinBox* _gain;
        };

        void LTPreviewerImpl::init()
        {
            OI_Q(LTPreviewer);

            QVBoxLayout* layout = new QVBoxLayout(q);


            _viewer = new CLTProfileView(q);
            _chart = _viewer->chart();

            layout->addWidget(_viewer);

            auto menuLayout = new QHBoxLayout;
            menuLayout->setContentsMargins(0, 0, 0, 0);
            
            auto saveButton = new QPushButton(LTPreviewer::tr("保存轮廓"));
            QObject::connect(saveButton, &QPushButton::clicked, q, &LTPreviewer::onSaveProfile);
            menuLayout->addWidget(saveButton);
            
            auto exposureLabel = new QLabel(LTPreviewer::tr("曝光时间"));
            menuLayout->addWidget(exposureLabel);
            _exposure = new QDoubleSpinBox;
            _exposure->setRange(10, 200);
            _exposure->setValue(LT360X::instance()->exposureTime());
            _exposure->setMinimumWidth(30);
            QObject::connect(_exposure, QOverload<double>::of(&QDoubleSpinBox::valueChanged), q, &LTPreviewer::onUpdateExposure);
            menuLayout->addWidget(_exposure);
            
            auto gainLabel = new QLabel(LTPreviewer::tr("增益"));
            menuLayout->addWidget(gainLabel);
            _gain = new QDoubleSpinBox;
            _gain->setRange(1., 20.);
            _gain->setValue(LT360X::instance()->gain());
            _gain->setMinimumWidth(20);
            QObject::connect(_gain, QOverload<double>::of(&QDoubleSpinBox::valueChanged), q, &LTPreviewer::onUpdateGain);
            menuLayout->addWidget(_gain);
            menuLayout->addStretch();

            layout->addLayout(menuLayout);

            q->setWindowTitle(LTPreviewer::tr("预览"));
            q->setGeometry(qApp->desktop()->availableGeometry().adjusted(34, 48, -24, 8));

            auto driver = LTCameraDriver::instance();
            driver->setCallback(LTPreviewerImpl::refresh, q);

            _updateTimer = new QTimer(q);
            _updateTimer->setSingleShot(false);
            _updateTimer->setInterval(100);
            QObject::connect(_updateTimer, &QTimer::timeout, q, &LTPreviewer::onUpdateChart);

           Appl::ToolSeries* boundingBox = new Appl::ToolSeries();

            //for (int i = 0; i < 101; i++)
            //{
            //    boundingBox->append(QPointF(25 * std::cos(CV_PI * 2 / 100 * i), 25 * std::sin(CV_PI * 2 / 100 * i)));
            //}
            boundingBox->append(QPointF(-255, -27));
            boundingBox->append(QPointF(+255, -27));
            boundingBox->append(QPointF(+255, +27));
            boundingBox->append(QPointF(-255, +27));
            boundingBox->append(QPointF(-255, -27));

            QPen pen(Qt::red);
            pen.setWidth(1);
            boundingBox->setPen(pen);
            _chart->addSeries(boundingBox);
            boundingBox->attachAxis(_chart->axisX());
            boundingBox->attachAxis(_chart->axisY());

            QMetaObject::invokeMethod(q, "onReady", Qt::QueuedConnection);
        }

        void LTPreviewerImpl::exit()
        {
            OI_Q(LTPreviewer);
            _updateTimer->stop();
            LTCameraDriver::instance()->stop();
            LTCameraDriver::instance()->setCallback(NULL, NULL);
        }

        void LTPreviewerImpl::refresh(const LTCameraFrame& frame, const QDateTime& timestamp, void* data)
        {
            auto q = static_cast<LTPreviewer*>(data);
            QMetaObject::invokeMethod(q, "onRefresh", Qt::QueuedConnection, Q_ARG(const LTCameraFrame&, frame), Q_ARG(const QDateTime&, timestamp));
        }

        LTPreviewer::LTPreviewer(QWidget* parent)
            : Ctrl::Dialog(parent)
        {
            OI_I(LTPreviewer)->init();

        }

        LTPreviewer::~LTPreviewer()
        {
            OI_E(LTPreviewer)->exit();
        }

        void LTPreviewer::onReady()
        {
            OI_F(LTPreviewer);
            d->_updateTimer->start();
            LTCameraDriver::instance()->setMaxROI();
            LTCameraDriver::instance()->start();
        }

        void LTPreviewer::onRefresh(const QMap<QString, Core::RangeMapPtr>& rangeMaps, const QDateTime& timestamp)
        {
            OI_F(LTPreviewer);
            d->_currentFrame = rangeMaps;
        }

        void LTPreviewer::onUpdateChart()
        {
            OI_F(LTPreviewer);

            QPen pen(Qt::cyan);
            pen.setWidth(2);

            QList<QPointF> points;
            LT360X::instance()->rangeMapsToPoints(d->_currentFrame, points);
            if (points.size() > 0)
            {
                auto  series = d->_chart->updateProfile(LTBase::pointCloudParser(points, LT360X::instance()->connectionThreshold(), LT360X::instance()->linkingThreshold(), LT360X::instance()->noiseThreshold()));
                for (auto& s : series)
                {
                    s->setPen(pen);
                }

                if (d->_autorange)
                {
                    d->_chart->autoRange(0.8);
                    d->_autorange = false;
                }
            }
        }

        void LTPreviewer::onSaveProfile()
        {
            OI_F(LTPreviewer);

            QList<QPointF> points;
            LT360X::instance()->rangeMapsToPoints(d->_currentFrame, points);
            if (points.size() > 0)
            {
                LTBase::SnapShot snapshot;
                snapshot.design << points;

                QString strPath = QFileDialog::getSaveFileName(this, LTPreviewer::tr("保存为模板"), LT360X::instance()->settingDir + QString("/%1").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss")), QObject::tr("des (*.des)"));

                if (!strPath.isEmpty())
                {
                    QFile file(strPath);
                    file.open(QFile::WriteOnly);
                    QDataStream outStream(&file);
                    outStream << snapshot;
                }

            }
        }

        void LTPreviewer::onUpdateExposure(double v)
        {
            LT360X::instance()->setExposureTime(v);
            LTCameraDriver::instance()->setExposure(v);
        }

        void LTPreviewer::onUpdateGain(double v)
        {
            LT360X::instance()->setGain(v);
            LTCameraDriver::instance()->setGain(v);
        }
    }
}

